from direct.particles.Particles import Particles
from direct.particles.ParticleEffect import ParticleEffect
#from src.enemies import model
from pandac.PandaModules import *    # basic Panda modules
from direct.interval.IntervalGlobal import *  # for compound intervals
from direct.task import Task         # for update fuctions
import cfg
import math

#you cant normalize in-place so this is a helper function
def myNormalize(myVec):
	myVec.normalize()
	return myVec

#helper function to make a rect given the Lower-Left-Hand and Upper-Right-Hand corners
def makeRect(x1,y1,z1, x2,y2,z2, rgb = (.9,0,0)):
    format=GeomVertexFormat.getV3n3cpt2()
    vdata=GeomVertexData('square', format, Geom.UHDynamic)

    vertex=GeomVertexWriter(vdata, 'vertex')
    normal=GeomVertexWriter(vdata, 'normal')
    color=GeomVertexWriter(vdata, 'color')
    texcoord=GeomVertexWriter(vdata, 'texcoord')

    #make sure we draw the sqaure in the right plane
    if x1!=x2:
            vertex.addData3f(x1, y1, z1)
            vertex.addData3f(x2, y1, z1)
            vertex.addData3f(x2, y2, z2)
            vertex.addData3f(x1, y2, z2)

            normal.addData3f(myNormalize(Vec3(2*x1-1, 2*y1-1, 2*z1-1)))
            normal.addData3f(myNormalize(Vec3(2*x1-1, 2*y1-1, 2*z1-1)))
            normal.addData3f(myNormalize(Vec3(2*x2-1, 2*y2-1, 2*z2-1)))
            normal.addData3f(myNormalize(Vec3(2*x2-1, 2*y2-1, 2*z2-1)))

    else:
            vertex.addData3f(x1, y1, z1)
            vertex.addData3f(x2, y2, z1)
            vertex.addData3f(x2, y2, z2)
            vertex.addData3f(x1, y1, z2)

            normal.addData3f(myNormalize(Vec3(2*x1-1, 2*y1-1, 2*z1-1)))
            normal.addData3f(myNormalize(Vec3(2*x2-1, 2*y2-1, 2*z1-1)))
            normal.addData3f(myNormalize(Vec3(2*x2-1, 2*y2-1, 2*z2-1)))
            normal.addData3f(myNormalize(Vec3(2*x1-1, 2*y1-1, 2*z2-1)))

    #adding different colors to the vertex for visibility
    color.addData4f(rgb[0],rgb[1],rgb[2],1.0)
    color.addData4f(rgb[0],rgb[1],rgb[2],1.0)
    color.addData4f(rgb[0],rgb[1],rgb[2],1.0)
    color.addData4f(rgb[0],rgb[1],rgb[2],1.0)

    texcoord.addData2f(0.0, 1.0)
    texcoord.addData2f(0.0, 0.0)
    texcoord.addData2f(1.0, 0.0)
    texcoord.addData2f(1.0, 1.0)

    #quads arent directly supported by the Geom interface
    #you might be interested in the CardMaker class if you are
    #interested in rectangle though
    tri1=GeomTriangles(Geom.UHDynamic)
    tri2=GeomTriangles(Geom.UHDynamic)

    tri1.addVertex(0)
    tri1.addVertex(1)
    tri1.addVertex(3)

    tri2.addConsecutiveVertices(1,3)

    tri1.closePrimitive()
    tri2.closePrimitive()


    square=Geom(vdata)
    square.addPrimitive(tri1)
    square.addPrimitive(tri2)

    return square

def makeLaser(x1, y1, z1, x2, y2, z2):
    rgb = (0,0.9,0)
    side1=makeRect(x1 + .1,y1 + .1,z1,x1,y1,z1+1000,rgb)

    snode=GeomNode('prism')
    snode.addGeom(side1)

    prism=render.attachNewNode(snode)
    #prism.setH(180)
    #prism.setP(90)
    #prism.lookAt((x2,y2,z2))
    #OpenGl by default only draws "front faces" (polygons whose vertices are specified CCW).
    prism.setTwoSided(True)
    return prism

class Projectile(object):
    def __init__(self, owner, pos, vx, vy, vz, targetObject, type):
        self.owner = owner
        self.targetObject = targetObject
        self.type = type
        self.time = 0
        self.pos = pos
        self.vx = vx
        self.vy = vy
        self.vz = vz
        #self.accept("bullet-hit-targetObject", self.hit)
        if self.type == "acid":
            self.actor = ActorNode("physics")
            self.model = render.attachNewNode(self.actor)
            self.frowney = loader.loadModel("../models/acid_ball.egg")
            self.frowney.setScale(.1)
            self.frowney.reparentTo(self.model)
            self.model.reparentTo(render)
            self.model.setPos(pos)
            #self.model.setZ(self.model.getZ() + 3)
            self.vx = vx * .5
            self.vy = vy * .5
            self.vz = vz * .5 - .6
            taskMgr.add(self.move, "projectileMove")
            self.setupCD(self.model, "acid", self.owner)
            #self.setupParticles()
            
        if self.type == "plasma":
            taskMgr.add(self.findTarget, "plasmaTarget")
            self.actor = ActorNode("physics")
            self.model = render.attachNewNode(self.actor)
            self.frowney = loader.loadModel("models/frowney")
            self.frowney.setScale(.1)
            self.frowney.reparentTo(self.model)
            #self.model.setPos(pos)
            self.pos[2] += 0.5
            self.vx = vx * .0001
            self.vy = vy * .0001
            self.vz = vz * .0001
            taskMgr.add(self.move, "projectileMove")
            self.setupCD(self.model, "plasma", self.owner)

        #edit to spawn a long line all at once
        if self.type == "laser":
            self.actor = ActorNode("physics")
            self.model = render.attachNewNode(self.actor)
            self.frowney = loader.loadModel("models/frowney")
            self.frowney.setScale(.1)
            self.frowney.reparentTo(self.model)
            self.model.reparentTo(render)
            self.model.setPos(pos)
            self.vx = vx * cfg.laserspeed
            self.vy = vy * cfg.laserspeed
            self.vz = vz * cfg.laserspeed - .1
            taskMgr.add(self.move, "projectileMove")
            self.setupCD(self.model, "laser", self.owner)
            #self.lasermodel = makeLaser(pos[0],pos[1],pos[2], pos[0] + 100*-self.vx, pos[1] + 100*-self.vy, pos[2] + 100*self.vz)
            #taskMgr.doMethodLater(.2, self.removeLaser, "removing laser model")
            
    def removeLaser(self, task):
        self.lasermodel.removeNode()
        return task.done

    def gotTarget(self):
        if self.targetObject == 0:
            return cfg.player.hitNode.getPos(render)
        else:
            return self.targetObject#.getBounds().getCenter()

    def findTarget(self, task):
        pass
        self.getEnemy = 0
        dist = 0
        if self.type == "plasma" and self.targetObject == cfg.enemy:
            if cfg.enemy.model and self.model:
                p_x = cfg.enemy.model.getX() - self.model.getX()
                p_y = cfg.enemy.model.getY() - self.model.getY()
                p_z = cfg.enemy.model.getZ() - self.model.getZ()
                dist = math.sqrt(math.pow(p_x, 2) + math.pow(p_y, 2) + math.pow(p_z, 2))
                if dist <= 5:
                    self.getEnemy = cfg.enemy.model.getPos()

                if self.getEnemy == 0:
                    self.targetObject = 0
                    self.gotTarget()
                else:
                    self.targetObject = self.getEnemy
                    self.gotTarget()
                    return task.done
        elif self.type == "plasma" and self.targetObject == cfg.player:
            if cfg.player.model and self.model:
                p_x = cfg.player.model.getX() - self.model.getX()
                p_y = cfg.player.model.getY() - self.model.getY()
                p_z = cfg.player.model.getZ() - self.model.getZ()
                dist = math.sqrt(math.pow(p_x, 2) + math.pow(p_y, 2) + math.pow(p_z, 2))
                if dist <= 5:
                    self.getEnemy = cfg.player.model.getPos()

                if self.getEnemy == 0:
                    self.targetObject = 0
                    self.gotTarget()
                else:
                    self.targetObject = self.getEnemy
                    self.gotTarget()
                    return task.done

            return task.cont

    def setupParticles(self):
        particles = Particles()
        particles.setPoolSize(10)
        particles.setBirthRate(0.01)
        particles.setLitterSize(2)
        particles.setLitterSpread(6)
        particles.setFactory("PointParticleFactory")
        particles.setRenderer("SparkleParticleRenderer")
        particles.setEmitter("SphereVolumeEmitter")
        #acidball = loader.loadModel("../models/acid_ball.egg")
        #acidball.setScale(.05)
        #particles.getRenderer().setGeomNode(acidball.node())
        self.effect = ParticleEffect("peffect", particles)
        self.effect.reparentTo(self.model)
        self.effect.enable()

    def endThrust(self, task):
        self.actor.getPhysical(0).removeLinearForce(self.thrusterForce)
        return Task.done

    def move(self, task):
        if self.type == "plasma":
            if self.owner == "player":
                self.target = cfg.enemy.model.getPos(render)
            else:
                self.target = cfg.player.model.getPos(render)

            #self.gotTarget()
            #print self.target
            self.dx = self.model.getX() - self.target.getX()#self.pos[0] - self.target[0]
            self.dy = self.model.getY() - self.target.getY()#self.pos[1] - self.target[1]
            self.dz = self.model.getZ() - self.target.getZ()#self.pos[2] - self.target[2]
            self.dt = math.sqrt(math.pow(self.dx, 2)+math.pow(self.dy, 2)+math.pow(self.dz, 2))
            self.dx /= (self.dt * 50)
            self.dy /= (self.dt * 50)
            self.dz /= (self.dt * 50)
            if math.pow(cfg.plasmaspeed, 2) > (math.pow(self.vx + self.dx, 2) + math.pow(self.vy + self.dy, 2) + math.pow(self.vz + self.dz, 2)):
                self.vx += self.dx
                self.vy += self.dy
                self.vz += self.dz
            self.pos[0] -= self.vx
            self.pos[1] -= self.vy
            self.pos[2] -= self.vz
            self.model.setPos(self.pos)
        if self.type == "laser":
            self.pos[0] -= self.vx
            self.pos[1] -= self.vy
            self.pos[2] -= self.vz
            self.model.setPos(self.pos)
        if self.type == "acid":
            self.vz += .02
            self.pos[0] -= self.vx
            self.pos[1] -= self.vy
            self.pos[2] -= self.vz
            self.model.setPos(self.pos)

        self.time += 1
        if self.model.getZ() < -100 or self.time > 500:
            self.model.removeNode()
            #self.effect.removeNode()
        else:
            return Task.cont
        
    def setupCD(self, model, type, owner):
        #base.cTrav = CollisionTraverser()
        self.cHandler = CollisionHandlerEvent()
        self.cHandler.addInPattern("%fn-hit-%in")
        cSphere = CollisionSphere((0,0,0), 0.25)
        cNode = CollisionNode(owner + "-" + type)
        cNode.addSolid(cSphere)
        cNodePath = model.attachNewNode(cNode)
        cNodePath.show()
        base.cTrav.addCollider(cNodePath, self.cHandler)
            
    def updateProjectiles(self, task):
        pass

